﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using HtmlAgilityPack;

namespace HtmlDeploy.Processors
{
    public class MasterPageProcessor
    {
        private readonly Dictionary<string, string> masterPages;

        public MasterPageProcessor(Dictionary<string, string> masterPages)
        {
            this.masterPages = masterPages;
            InitMasterPages();
        }

        private void InitMasterPages()
        {
            var needsCompile = new List<string>();
            var noCompile = new List<string>();

            foreach (var masterPage in masterPages)
            {
                if (string.IsNullOrEmpty(ResolveMasterPageName(masterPage.Value)))
                    noCompile.Add(masterPage.Key);
                else
                    needsCompile.Add(masterPage.Key);
            }

            if (needsCompile.Count == 0)
                return;

            foreach (var compile in needsCompile)
                masterPages[compile] = HydrateWithMasterPage(masterPages[compile]);

            //Keep on doing this until needsCompile is zero
            InitMasterPages();
        }

        public string Compile(string filePath)
        {
            using (var sr = new StreamReader(filePath))
            {
                return CompileSrc(sr.ReadToEnd());
            }
        }

        private string CompileSrc(string src)
        {
            var masterPage = ResolveMasterPageName(src);

            //nothing to compile
            if (string.IsNullOrEmpty(masterPage))
                return src;

            return HydrateWithMasterPage(src);
        }

        private string HydrateWithMasterPage(string src)
        {
            var masterPageName = ResolveMasterPageName(src);

            if (string.IsNullOrEmpty(masterPageName))
                return src;

            var masterPageTemplate = masterPages[masterPageName];
            //put stuff in <asp:content> into the masterpage's <asp:ContentPlaceHolder>

            var masterDoc = new HtmlDocument();
            masterDoc.LoadHtml(masterPageTemplate);
            masterDoc.OptionWriteEmptyNodes = true;

            var placeHolders = masterDoc.DocumentNode.Descendants().Where(x => x.Name == "asp:contentplaceholder");

            var childDoc = new HtmlDocument();
            childDoc.LoadHtml(src);
            childDoc.OptionWriteEmptyNodes = true;

            foreach(var contentTag in childDoc.DocumentNode.Descendants().Where(x=> x.Name == "asp:content"))
            {
                var placeHolder =
                    placeHolders.Where(x => x.Id == contentTag.GetAttributeValue("ContentPlaceHolderID", ""))
                        .SingleOrDefault();
                
                if(placeHolder == null)
                    continue;

                placeHolder.AppendChild(contentTag);

                contentTag.ParentNode.RemoveChild(contentTag, true);
                placeHolder.ParentNode.RemoveChild(placeHolder, true);
            }

            return RemovePageDirective(masterDoc.DocumentNode.InnerHtml).Trim();
        }

        private static string RemovePageDirective(string src)
        {
            var start = src.IndexOf("<%@");

            if (start == -1)
                return src;

            var end = src.IndexOf("%>", start);

            if (end == -1)
                return src;

            return RemovePageDirective(src.Substring(end + 2));
        }

        private static string ResolveMasterPageName(string src)
        {
            var start = src.IndexOf("<%@");

            if (start == -1)
                return "";

            var end = src.IndexOf("%>", start);

            if (end == -1)
                return "";


            var pageDirective = src.Substring(start, end - start);

            start = pageDirective.IndexOf("MasterPageFile=");

            if (start == -1)
                return "";

            end = pageDirective.IndexOf("\"", start + "MasterPageFile=".Length + 1);

            var filePath = pageDirective.Substring(start, end - start);

            if (!filePath.ToLower().EndsWith(".master"))
                throw new NotSupportedException("MasterPage must end with .Master, check the source: \n" + src);

            return filePath.Substring(filePath.ToLower().LastIndexOf("/") + 1);
        }
    }
}
